﻿using System.Media;
using System.Windows;
using System.Windows.Media;
using FanaticRock.AudioManage.Helpers;
using FanaticRock.Core.AudioPlay;
using FanaticRock.Core.AudioPlay.Events;
using FanaticRock.Core.AudioPlay.Exceptions;
using FanaticRock.Core.DI;
using FanaticRock.Core.Helpers;
using FanaticRock.Core.Models;
using FanaticRock.Core.ServiceInterfaces;

namespace FanaticRock.AudioManage.Services
{
    [InjectMe(typeof(IAudioPlayService))]
    public class AudioPlayService : IAudioPlayService
    {
        #region events

        public event EventHandler<AudioPlayStateChangedEventArgs> PlayStateChanged;

        public event EventHandler<AudioProgressUpdateEventArgs> AudioProgressUpdated;

        public event EventHandler MediaPlayEnd;

        #endregion

        #region fields

        private AudioPlayStateEnum _state = AudioPlayStateEnum.Unready;

        private MediaPlayer _mediaPlayer = new MediaPlayer();

        private Uri _currentAudioUri;

        private System.Timers.Timer _timer = new System.Timers.Timer(TimeSpan.FromMilliseconds(100));

        #endregion

        #region ctors

        public AudioPlayService()
        {
            _mediaPlayer.MediaEnded += _mediaPlayer_MediaEnded;
            _mediaPlayer.MediaFailed += _mediaPlayer_MediaFailed;
            _mediaPlayer.MediaOpened += _mediaPlayer_MediaOpened;

            _timer.Elapsed += _timer_Elapsed;
            _timer.Start();

            Application.Current.Exit += Current_Exit;
        }

        private void Current_Exit(object sender, ExitEventArgs e)
        {
            _timer.Stop();
        }

        private void _timer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
        {
            Application.Current.Dispatcher.InvokeAsync(() =>
            {
                var currentPos = _mediaPlayer.Position;
                var totalDur = DurationHelper.ToTimeSpan(_mediaPlayer.NaturalDuration);
                currentPos = TimeSpanHelper.Min(currentPos, totalDur);
                var args = new AudioProgressUpdateEventArgs()
                {
                    CurrentPosition = currentPos,
                    TotalDuration = totalDur,
                    State = _state,
                };
                AudioProgressUpdated?.Invoke(this, args);
            });

        }

        private void _mediaPlayer_MediaOpened(object? sender, EventArgs e)
        {

        }

        private void _mediaPlayer_MediaFailed(object? sender, ExceptionEventArgs e)
        {

        }

        private void _mediaPlayer_MediaEnded(object? sender, EventArgs e)
        {
            SetState(AudioPlayStateEnum.Stoped);
            MediaPlayEnd?.Invoke(this, e);
        }

        #endregion

        #region impls

        public AudioPlayStateEnum GetState()
        {
            return _state;
        }

        ///<summary>打开指定 Uri 的音乐。</summary>
        public async Task<bool> Open(Uri uri)
        {
            _currentAudioUri = uri;

            _mediaPlayer.Open(uri);

            return true;
        }

        public async Task Play()
        {
            _mediaPlayer.Play();
            SetState(AudioPlayStateEnum.Playing);
       
        }

        ///<summary>刷新</summary>
        public async Task Refresh()
        {
            _mediaPlayer.Stop();
            _mediaPlayer.Open(null);
        }

        public async Task Pause()
        {
            _mediaPlayer.Pause();

            SetState(AudioPlayStateEnum.Paused);

        }

        public async Task SetPosition(TimeSpan position)
        {
            _mediaPlayer.Position = position;
        }

        public async Task Replay()
        {
            SetPosition(TimeSpan.Zero);
            _mediaPlayer.Play();

            SetState(AudioPlayStateEnum.Playing);
        }


        private void SetState(AudioPlayStateEnum state)
        {
            if (state == _state) return;
            _state = state;
            PlayStateChanged?.Invoke(this, new AudioPlayStateChangedEventArgs()
            {
                State = _state
            });
        }

        public void SetVolume(double volumeRatio)
        {
            _mediaPlayer.Volume = volumeRatio;
        }

        public double GetVolume()
        {
           return _mediaPlayer.Volume;
        }

        #endregion


    }
}
